/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package game;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.icefaces.application.PortableRenderer;
import org.icefaces.application.PushRenderer;
import other.Costants;

/**
 *
 * @author alessandro
 */
public class Table implements Serializable {
    private List<String> userWatching = new ArrayList<String>();
    private List<String> userPlaying = new ArrayList<String>();

    private String status;
    private String creator;
    private int bots;
    private String name;
    private String message;
    private Deck deck;
    private ArrayList<String> winners = new ArrayList<String>();
    boolean start = false;
    PortableRenderer pr;

    public Table(String creator, int bots, String name) {
        this.message = Costants.TABLE_WELCOME;
        this.addBots(bots);
        this.creator = creator;
        this.status = Costants.READY;
        deck = new Deck();       
        this.name = name;
    }




    /* GETTERS AND SETTERS */
      public ArrayList<String> getWinners() {
        return winners;
    }

    public void setWinners(ArrayList<String> winners) {
        this.winners = winners;
    }
    public String getStatus() {
        return status;
    }
    public void setStatus(String status) {
        this.status = status;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    public int getUserWatchingNumber() {
        return userWatching.size();
    }
    public int getUserPlayingNumber() {
        return userPlaying.size();
    }
    public String getCreator() {
        return creator;
    }
    public void setCreator(String creator) {
        this.creator = creator;
    }
    public Deck getDeck() {
        return deck;
    }
    public void setDeck(Deck deck) {
        this.deck = deck;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getBots() {
        return bots;
    }
    public void setBots(int bots) {
        this.bots = bots;
    }
    public ArrayList<String> getUserPlaying() {
        return (ArrayList<String>) userPlaying;
    }
    public void setUserPlaying(List<String> userPlaying) {
        this.userPlaying = userPlaying;
    }
    public List<String> getUserWatching() {
        return userWatching;
    }
    public void setUserWatching(List<String> userWatching) {
        this.userWatching = userWatching;
    }

    /* METODI */
    private void addBots(int bots) {
        for (int i = 0; i < bots; i++) {
            userPlaying.add(Costants.BOTNAME + i);
        }
    }

    public void setNewUserWatching(String user) {
        if (!(this.isWatching(user))) {
            userWatching.add(user);
        }
    }

    public void revomeUserWatching(String user) {
        userWatching.remove(user);
    }

    public void removeUserPlaying(String user) {
        if (this.isStarted()) {
            userPlaying.set(this.getPlayerId(user), Costants.BOTNAME + this.numberBots());
            this.checkTurn();
        } else {
            userPlaying.remove(user);
        }
    }
    public int numberBots() {
        int botts = 0;
        for(int i=0; i<userPlaying.size(); i++){
            if(userPlaying.get(i).startsWith(Costants.BOTNAME)) {
                botts = botts + 1;
            }
        }
        return botts;
    }
    public boolean isWatching(String user) {
        boolean flag = false;
        for(int i=0; i<userWatching.size(); i++) {
            if(userWatching.get(i).equals(user)){
                flag = true;
                return flag;
            }
        }
        return flag;
    }
    public boolean isPlaying(String user) {
        boolean flag = false;
        for (int i = 0; i < userPlaying.size(); i++) {
            if (userPlaying.get(i).equals(user)) {
                flag = true;
                return flag;
            }
        }
        return flag;
    }
    public boolean isFull() {
        boolean flag = false;
        if(this.getPlayersList().size() == 4){
            flag = true;
        }
        return flag;
    }
    /* ottieni la lista dei nomi dei giocatori (prima gli user poi i bots) - IMPORTANTE PER LA VIEW*/
    public List<String> getPlayersList() {
        return userPlaying;
    }
    /* l'attuale numero di giocatori seduti ad un tavolo (users + bots)*/
    public int getPlayersNumber() {
        return this.getPlayersList().size();
    }
    /*controllo se il gioco è iniziato*/
    public boolean isStarted() {
        if(this.status.equals(Costants.STARTED)) 
            return true;
         else
            return false;
    }
    /* aggiunge un giocatore alla lista user e controlla se la lista è piena */
    public void addUserPlaying(String username) {
        if (!(this.isPlaying(username)) && !this.isFull()) {
            userPlaying.add(username);
            if (this.isFull()) {
                System.out.println("THE GAME IS RUN!");
                this.startGame();
            }
        }
    }
    /* chiede al deck se c'è una carta di un giocatore sul tavolo */
    public Card getCardonTable(String username) {
        Card card = null;

        ArrayList<Card> cards = this.getCardsPlayer(username);
        if (cards != null) {
            for (int i = 0; i < cards.size(); i++) {
                if (cards.get(i).getState().equals(Costants.ON_TABLE)) {
                    //System.out.println("CARTA di " + username + ": " + cards.get(i).getSeed() + cards.get(i).getNumber() + " stato:" + cards.get(i).getState());
                    return cards.get(i);
                }
            }
        }

        return card;
    }
    /*Date le carte di un giocatore da in output la carte sul tavolo */
    public Card getOnTableCard(ArrayList<Card> cards) {
        Card card = null;
        if(cards != null) {
            for(int i = 0; i < cards.size(); i++) {
                if(cards.get(i).getState().equals(Costants.ON_TABLE)) {
                    return cards.get(i);
                }
            }
        }
        return card;
    }
    /*Da in output l'id del giocatore tra tutti i giocatori (compresi i bot) */
    public int getPlayerId(String username) {
        int id = -1;
        for (int i = 0; i < userPlaying.size(); i++) {
            if(userPlaying.get(i).equals(username)) {
                return i;
            }
        }

        return id;
    }
    /* cerca le carte possedute da un giocatore dal suo nickname */
    public ArrayList<Card> getCardsPlayer(String username) {
        ArrayList<Card> cards = new ArrayList<Card>();
        int playerId = this.getPlayerId(username);
        switch (playerId) {
            case -1:
                return null;
            case 0:
                //System.out.println(username + " id:" + this.getPlayerId(username) + "Prima Carta:" + deck.getCardsPlayer1().get(deck.getCardsPlayer1().size() - 1).getSeed() + deck.getCardsPlayer1().get(deck.getCardsPlayer1().size() - 1).getNumber());
                return deck.getCardsPlayer1();
            case 1:
                //System.out.println(username + " id:" + this.getPlayerId(username) + "Prima Carta:" + deck.getCardsPlayer2().get(deck.getCardsPlayer2().size() - 1).getSeed() + deck.getCardsPlayer2().get(deck.getCardsPlayer2().size() - 1).getNumber());
                return deck.getCardsPlayer2();

            case 2:
                //System.out.println(username + " id:" + this.getPlayerId(username) + "Prima Carta:" + deck.getCardsPlayer3().get(deck.getCardsPlayer3().size() - 1).getSeed() + deck.getCardsPlayer3().get(deck.getCardsPlayer3().size() - 1).getNumber());
                return deck.getCardsPlayer3();
            case 3:
                //System.out.println(username + " id:" + this.getPlayerId(username) + "Prima Carta:" + deck.getCardsPlayer4().get(deck.getCardsPlayer4().size() - 1).getSeed() + deck.getCardsPlayer4().get(deck.getCardsPlayer4().size() - 1).getNumber());
                return deck.getCardsPlayer4();
        }

        return cards;
    }

    private void setFirstSeed(String seed) {
        //set seme della prima carta che costringe gli altri a giocare lo stesso seme
        System.out.println("FirstSeed: " + deck.getFirstSeed());
        if (deck.getTableCards().size()== 1) {
            deck.setFirstSeed(seed);
        }
        System.out.println("FirstSeed: " + deck.getFirstSeed());
    }
    /* mischia le carte, le da ai giocatori e fa partire il gioco */
    public void startGame() {
        status = Costants.STARTED;

        deck.shuffleCards();
        deck.startGivingCards();

        message = Costants.TABLE_GAME_START + " 3..";
        PushRenderer.render(Costants.PUSH_TABLE);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(Table.class.getName()).log(Level.SEVERE, null, ex);
        }
        message = Costants.TABLE_GAME_START + " 2..";
        PushRenderer.render(Costants.PUSH_TABLE);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(Table.class.getName()).log(Level.SEVERE, null, ex);
        }
        message = Costants.TABLE_GAME_START + " 1..";
        PushRenderer.render(Costants.PUSH_TABLE);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(Table.class.getName()).log(Level.SEVERE, null, ex);
        }
        start = true;
        checkTurn();
        start = false;

      

    }
    /*metodo per far giocare una carta ad un user */
    public boolean play(String username, String card) {
        boolean flag = false;
        //set seme della prima carta che costringe gli altri a giocare lo stesso seme   
        int idPlayer = this.getPlayerId(username);
        deck.setCardPlayerOnTable(idPlayer, card);
        deck.setToken(deck.getToken() + 1); //dopo aver giocato passo il turno
        //message = Costants.TABLE_PLAYER_TURN + " " + this.getPlayersList().get(deck.getToken());
        PushRenderer.render(Costants.PUSH_TABLE);
        this.setFirstSeed(card.substring(0, 1));
        if(card.substring(0, 1).equals(Costants.SEED_C)) {
            deck.setHeartsBroken(true);
        }
        this.checkTurn();
        flag = true;
        return flag;
    }
    /*check sulle 4 carte sul tavolo per ogni giocatore e per il turno dei bot. Calcola anche i punteggi*/
    public void checkTurn() {

        /* CONTROLLO SULLE 4 CARTE */
        if (!(deck.checkFourCards())) {
            //vedo se il giocatore che deve giocare è un bot
            if (this.getPlayersList().get(deck.getToken()).startsWith(Costants.BOTNAME)) {
                Card card = null;
                switch (deck.getToken()) {
                    case 0:
                        card = BOT.play(deck.getCardsFromStatus(deck.getCardsPlayer1(), Costants.HOLD_BY_USER),deck.getFirstSeed(), deck.isHeartsBroken());
                        deck.getCardsPlayer1().remove(card);
                        card.setState(Costants.ON_TABLE);
                        deck.getCardsPlayer1().add(card);
                        message = Costants.TABLE_PLAYER_TURN + " " + this.getPlayersList().get(deck.getToken());
                        //PushRenderer.render(Costants.PUSH_TABLE);
                        //System.out.println("Giocatore 1 play:" + card.getSeed() + card.getNumber());
                        //System.out.println("ULTIMA CARTA GIOCATORE 1:"+deck.getCardsPlayer1().get(deck.getCardsPlayer1().size()-1).getSeed());
                        break;
                    case 1:
                        card = BOT.play(deck.getCardsFromStatus(deck.getCardsPlayer2(), Costants.HOLD_BY_USER), deck.getFirstSeed(), deck.isHeartsBroken());

                        deck.getCardsPlayer2().remove(card);
                        card.setState(Costants.ON_TABLE);
                        deck.getCardsPlayer2().add(card);
                        message = Costants.TABLE_PLAYER_TURN + " " + this.getPlayersList().get(deck.getToken());
                        //PushRenderer.render(Costants.PUSH_TABLE);
                        //System.out.println("Giocatore 2 play:" + card.getSeed() + card.getNumber());
                        //System.out.println("ULTIMA CARTA GIOCATORE 2:"+deck.getCardsPlayer2().get(deck.getCardsPlayer2().size()-1).getSeed());
                        break;
                    case 2:
                        card = BOT.play(deck.getCardsFromStatus(deck.getCardsPlayer3(), Costants.HOLD_BY_USER),deck.getFirstSeed(), deck.isHeartsBroken());
                        deck.getCardsPlayer3().remove(card);
                        card.setState(Costants.ON_TABLE);
                        deck.getCardsPlayer3().add(card);
                        message = Costants.TABLE_PLAYER_TURN + " " + this.getPlayersList().get(deck.getToken());
                        //PushRenderer.render(Costants.PUSH_TABLE);
                        //System.out.println("Giocatore 3 play:" + card.getSeed() + card.getNumber());
                        //System.out.println("ULTIMA CARTA GIOCATORE 3:"+deck.getCardsPlayer3().get(deck.getCardsPlayer3().size()-1).getSeed());
                        break;
                    case 3:
                        card = BOT.play(deck.getCardsFromStatus(deck.getCardsPlayer4(), Costants.HOLD_BY_USER),deck.getFirstSeed(), deck.isHeartsBroken());
                        deck.getCardsPlayer4().remove(card);
                        card.setState(Costants.ON_TABLE);
                        deck.getCardsPlayer4().add(card);
                        message = Costants.TABLE_PLAYER_TURN + " " + this.getPlayersList().get(deck.getToken());
                        //PushRenderer.render(Costants.PUSH_TABLE);
                        //System.out.println("Giocatore 4 play:" + card.getSeed() + card.getNumber());
                        //System.out.println("ULTIMA CARTA GIOCATORE 4:"+deck.getCardsPlayer4().get(deck.getCardsPlayer4().size()-1).getSeed());
                        break;
                }
                System.out.println("CARTA GIOCATA DAL BOT: " + card.getSeed() + card.getNumber());

                if (card != null) {
                    this.setFirstSeed(card.getSeed());
                    if(card.getSeed().equals(Costants.SEED_C)) {
                        deck.setHeartsBroken(true);
                    }
                }
                deck.setToken(deck.getToken() + 1);
                checkTurn();
            }
            message = Costants.TABLE_PLAYER_TURN + " " + this.getPlayersList().get(deck.getToken());
        } else {
            message = Costants.TABLE_NEW_TURN;
            PushRenderer.render(Costants.PUSH_TABLE);
        }
        PushRenderer.render(Costants.PUSH_TABLE);
        
    }
    /* fine turno */
    public void endTurn() {
         if (deck.checkFourCards()) {
            System.out.println("TURNO FINITO!");
            deck.endTurn();
            System.out.println("Round: "+deck.getRound());
            if (deck.getRound() == 13) {
                System.out.println("PARTITA FINITA!");
                this.endGame();

            } else {
                deck.setFirstSeed(null);
                this.checkTurn();
            }
            PushRenderer.render(Costants.PUSH_TABLE);
        }
    }
    /* fine della partita */
    private void endGame() {
        System.out.println("IL GIOCO E' FINITO!");
        //calcolo punteggi
        ArrayList<Integer> winnerIndex = deck.getWinner();
        if (winnerIndex.size() > 1) { // 2 vincitori
            message = Costants.TABLE_THE_WINNER_ARE;
            for(int i=0; i < winnerIndex.size(); i++) {
                String winner = this.getPlayersList().get(winnerIndex.get(i));
                winners.add(winner);
                message = message + winner + " ";
            }
            message = message + "!";
        } else { // 1 vincitori
            String winner = this.getPlayersList().get(winnerIndex.get(0));
            winners.add(winner);
            message = Costants.TABLE_THE_WINNER_IS  + winner + "!";
        }

        PushRenderer.render(Costants.PUSH_TABLE);

    }
}
